// 该文件中的代码旨在完成对安装确认后的条件的核验，
// 总概括代码的返回值可提供至引用它的地方，供上级代码参考。


// 头文件引用
// 官方库
#include <cstring>
#include <fstream>
#include <filesystem>
#include <sys/stat.h> // 用于stat函数

// 第三方库
#include "md5file.h"

// 项目专用函数库
#include "GetEnvironmentCommon.h"





// 使用stat函数（跨平台）检测目标文件是否存在
bool exists_stat(const std::string& path) {
    struct stat buffer;
    return (stat(path.c_str(), &buffer) == 0) && !(buffer.st_mode & S_IFDIR);
}
// 检测文件是否存在
bool CheckFileExist(std::string RelativePath) {
    bool Flag_CheckFileExist;

    // 使用stat方法检测
    if (exists_stat(RelativePath))
        Flag_CheckFileExist = true; // 存在
    else
        Flag_CheckFileExist = false; // 不存在

    return Flag_CheckFileExist;
}


// 检测文件 MD5 是否符合预设值
bool CheckMD5(std::string Subdirectory, std::string Product_FileName, std::string Product_MD5_Data) {

    // 获取现有文件的 MD5 值
    std::string FileMD5 = getFileMD5(Subdirectory, Product_FileName);

    // MD5获取值 与 MD5预设值 比较
    Product_MD5_Data = Product_MD5_Data + '\0';

    bool MD5_Flag; // MD5 是否符合预设 的标记

    if (FileMD5.compare(Product_MD5_Data) == 0)
        MD5_Flag = true; // 符合预设值
    else
        MD5_Flag = false; // 不符合预设值

    return MD5_Flag;
}


// 检测用户分区空间是否足够
// 函数：检查目录是否可写入
bool isDirectoryWritable(const std::string& path) {
    std::filesystem::path dirPath(path);
    if (!std::filesystem::exists(dirPath) || !std::filesystem::is_directory(dirPath)) {
        return false;
    }

    // 尝试在目录中创建一个临时文件
    std::filesystem::path tempFile = dirPath / "tempwr_xw5cqx3u.txt";
    std::ofstream ofs(tempFile);
    if (!ofs) {
        return false;
    }
    ofs.close();
    std::filesystem::remove(tempFile); // 删除临时文件
    return true;
}


// 函数：检查分区存储空间是否大于1GB
bool isPartitionSpaceGreaterThan1GB(const std::string& path) {
    std::filesystem::space_info space = std::filesystem::space(path);
    return space.available > 1 * 1024 * 1024 * 1024; // 1GB = 1 * 1024 * 1024 * 1024 bytes
}


// 函数：检查目录是否可写入 与 函数：检查分区存储空间是否大于1GB 合并体
// CN: 检测客观安装条件
// EN: Detect objective installation conditions
bool DOInstallationC(const std::string& path) {
    bool CheckWrite = false, CheckSpace = false;
    CheckWrite = isDirectoryWritable(path);
    if (CheckWrite)
        CheckSpace = isPartitionSpaceGreaterThan1GB(path);
    return CheckSpace;  // 判断逻辑：储存空间够，必可写入；可写入，储存空间未必够（判断的先后顺序）
}


// 检测 D 分区 或 C 分区是否能够写入且存储空间足够
int CheckInstallDorC() {
    std::string InstallPathD = "D:\\";
    std::string InstallPathC = "C:\\";
    int CheckFlag = 0;
    if (DOInstallationC(InstallPathD))
        CheckFlag = 1;
    else if (DOInstallationC(InstallPathC))
        CheckFlag = 2;
    return CheckFlag;
}



// 点击安装按钮后，检查用户是否有目标环境的安装条件
int CheckDevEnvironmentB(std::string Product_FileName, std::string Subdirectory,
                        std::string RelativePath, std::string Product_MD5_Data) {

    int CheckDevEnvironmentB_Return; // 创建返回表
    // 返回表数值含义：
    // 0 - 存储空间不足
    // 1 - 安装到 D:\
    // 2 - 安装到 C:\
    // 3 - 文件MD5不符合预设
    // 4 - 文件（环境文件压缩包）不存在

    bool Flag_CheckFileExist = CheckFileExist(RelativePath); // 检查环境压缩包是否存在
    if (Flag_CheckFileExist) {
        bool GetInstallMD5 = CheckMD5(Subdirectory, Product_FileName, Product_MD5_Data); // 检查环境包MD5是否符合预定值
        if (GetInstallMD5) {
            int GetInstallPosition = CheckInstallDorC();  // 逐次检查D区、C区的文件解压客观条件，并得出解压后文件所在的分区
            CheckDevEnvironmentB_Return = GetInstallPosition; // 得出安装位置 1 - 安装到 D:\；2 - 安装到 C:\；0 - 存储空间不足或文件无法被正常写入
        }
        else
            CheckDevEnvironmentB_Return = 3; // 3 - 文件MD5不符合预设
    }
    else
        CheckDevEnvironmentB_Return = 4; // 4 - 文件（环境文件压缩包）不存在

    return CheckDevEnvironmentB_Return;
}